package com.lap.permission.aop;

import com.lap.framework.dto.DeviceDTO;
import com.lap.framework.exception.BizException;
import com.lap.framework.i18n.helper.MessageHelper;
import com.lap.framework.tools.ClientIpUtil;
import com.lap.framework.tools.DeviceUtil;
import com.lap.permission.component.RequestHelper;
import com.lap.permission.dto.request.LoginRequest;
import com.lap.permission.event.entity.LoginLogEvent;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 登录日志 AOP
 *
 * @author Shuisheng Lao(劳水生)
 * @version 0.0.1
 */
@Slf4j
@Component
@Aspect
public class LoginAspect {

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    protected MessageHelper messageHelder;

    @Pointcut("@annotation(com.lap.permission.annotation.LoginLog)")
    public void loginPointcut() {
    }

    @Around("loginPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        String remark = "Success";
        int flag = 1;
        try {
            return joinPoint.proceed();
        } catch (Throwable e) {
            remark = getRemark(e);
            flag = 0;
            throw e;
        } finally {
            stopWatch.stop();
            long times = stopWatch.getTime(TimeUnit.MILLISECONDS);
            String username = getUsername(joinPoint.getArgs());
            publishLoginLog(times, username, flag, remark);
        }
    }

    private String getRemark(Throwable e) {
        return (e instanceof BizException biz)
                ? messageHelder.getMsg(biz.getCode())
                : e.getLocalizedMessage();
    }

    private String getUsername(Object[] arg) {
        return (ArrayUtils.isNotEmpty(arg) && arg[0] instanceof LoginRequest logs)
                ? logs.getUsername()
                : null;
    }

    private void publishLoginLog(long times, String username, Integer statusFlag, String remark) {
        HttpServletRequest request = RequestHelper.getRequest();
        DeviceDTO device = DeviceUtil.getDevice(request);
        String ip = ClientIpUtil.getClientIp(request);

        LoginLogEvent event = LoginLogEvent
                .builder()
                .ip(ip)
                .username(username)
                .device(device)
                .statusFlag(statusFlag)
                .times(times)
                .remark(remark)
                .build();

        applicationContext.publishEvent(event);
    }

}
